#include "gd32w51x.h"
#include "stdint.h"
#include "stdio.h"
#include "ff.h"
#include "lfs.h"
#include "lfs_util.h"
#include "DevicesSDCard.h"

/* information of SD card */
sd_card_info_struct sd_cardinfo;
/* FatFs文件系统对象 */
FATFS g_FATMountHanle = {0};

/*!
    \brief      get the card information and print it out by USRAT
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void card_info_get(void)
{
    uint8_t sd_spec, sd_spec3, sd_spec4, sd_security;
    uint32_t block_count, block_size;
    uint16_t temp_ccc;
    printf("\r\n Card information:");
    sd_spec = (sd_scr[1] & 0x0F000000) >> 24;
    sd_spec3 = (sd_scr[1] & 0x00008000) >> 15;
    sd_spec4 = (sd_scr[1] & 0x00000400) >> 10;
    if(2 == sd_spec){
        if(1 == sd_spec3){
            if(1 == sd_spec4){
                printf("\r\n## Card version 4.xx ##");
            }else{
                printf("\r\n## Card version 3.0x ##");
            }
        }else{
            printf("\r\n## Card version 2.00 ##");
        }
    }else if(1 == sd_spec){
        printf("\r\n## Card version 1.10 ##");
    }else if(0 == sd_spec){
        printf("\r\n## Card version 1.0x ##");
    }

    sd_security = (sd_scr[1] & 0x00700000) >> 20;
    if(2 == sd_security){
        printf("\r\n## SDSC card ##");
    }else if(3 == sd_security){
        printf("\r\n## SDHC card ##");
    }else if(4 == sd_security){
        printf("\r\n## SDXC card ##");
    }

    block_count = (sd_cardinfo.card_csd.c_size + 1)*1024;
    block_size = 512;
    printf("\r\n## Device size is %dKB ##", sd_card_capacity_get());
    printf("\r\n## Block size is %dB ##", block_size);
    printf("\r\n## Block count is %d ##", block_count);

    if(sd_cardinfo.card_csd.read_bl_partial){
        printf("\r\n## Partial blocks for read allowed ##" );
    }
    if(sd_cardinfo.card_csd.write_bl_partial){
        printf("\r\n## Partial blocks for write allowed ##" );
    }
    temp_ccc = sd_cardinfo.card_csd.ccc;
    printf("\r\n## CardCommandClasses is: %x ##", temp_ccc);
    if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc)){
        printf("\r\n## Block operation supported ##");
    }
    if(SD_CCC_ERASE & temp_ccc){
        printf("\r\n## Erase supported ##");
    }
    if(SD_CCC_WRITE_PROTECTION & temp_ccc){
        printf("\r\n## Write protection supported ##");
    }
    if(SD_CCC_LOCK_CARD & temp_ccc){
        printf("\r\n## Lock unlock supported ##");
    }
    if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc){
        printf("\r\n## Application specific supported ##");
    }
    if(SD_CCC_IO_MODE & temp_ccc){
        printf("\r\n## I/O mode supported ##");
    }
    if(SD_CCC_SWITCH & temp_ccc){
        printf("\r\n## Switch function supported ##");
    }
}




FRESULT scan_files (
    char* path        /* Start node to be scanned (***also used as work area***) */
)
{
    FRESULT res;
    DIR dir;
    UINT i;
    static FILINFO fno;


    /* Open the directory */
    res = f_opendir(&dir, path);
    if (res == FR_OK)
    {
        while(1)
        {
            /* Read a directory item */
            res = f_readdir(&dir, &fno);
            /* Break on error or end of dir */
            if (res != FR_OK || fno.fname[0] == 0)
                break;

            /* It is a directory */
            if (fno.fattrib & AM_DIR)
            {
                i = strlen(path);
                sprintf(&path[i], "/%s", fno.fname);

                /* Enter the directory */
                res = scan_files(path);
                if (res != FR_OK)
                    break;

                path[i] = 0;
            }
            /* It is a file. */
            else
            {
                printf("%s/%s\n", path, fno.fname);
            }
        }

        f_closedir(&dir);
    }

    return res;
}


/*!
    \brief      initialize the card, get the card information, set the bus mode and transfer mode
    \param[in]  none
    \param[out] none
    \retval     sd_error_enum
*/
sd_error_enum vSDCardInit(void)
{
    lfs_t lfs = {0};
    FRESULT res_sd;     /* 文件操作结果 */
    sd_error_enum status = SD_OK;
    uint32_t cardstate = 0, i = 0;

    nvic_irq_enable(SDIO_IRQn, 2, 0);

    for(i = 0; i < 5; ++i)
    {
        status = sd_init();
        if(SD_OK == status){
            status = sd_card_information_get(&sd_cardinfo);
        }
        if(SD_OK == status){
            status = sd_card_select_deselect(sd_cardinfo.card_rca);
        }
        status = sd_cardstatus_get(&cardstate);
        if(cardstate & 0x02000000){
            printf("\r\n the card is locked!");
            while(1){
            }
        }
        if ((SD_OK == status) && (!(cardstate & 0x02000000))){
            /* set bus mode */
            status = sd_bus_mode_config(SDIO_BUSMODE_1BIT);
        }
        if (SD_OK == status){
            /* set data transfer mode */
            status = sd_transfer_mode_config(SD_DMA_MODE);
        }
    }

    if(status != SD_OK)
    {
        printf("vSDCardInit status: %d\r\n", status);
        return status;
    }

    card_info_get();

    sd_lock_unlock(SD_UNLOCK);



    // int err = lfs_mount(&lfs, &g_LittleFSRomCfg);
    // printf("\n\rlfs_mount err: %d\r\n", err);
    // if(err)
    // {
    //     lfs_format(&lfs, &g_LittleFSRomCfg);
    //     int err = lfs_mount(&lfs, &g_LittleFSRomCfg);
    //     printf("lfs_mount err: %d\r\n", err);
    // }


    static char buff[256] = {0};

    res_sd = f_mount(&g_FATMountHanle, "0:", 1);
    if (res_sd == FR_OK)
    {
        strcpy(buff, "0:");
        res_sd = scan_files(buff);
    }


    return status;
}
